﻿using SuperSocket.ProtoBase;
using System;
using System.Buffers;
using System.Collections.Specialized;
using System.IO;
using System.Text;

namespace SuperSocket.Client.HttpCode;

internal abstract class HttpHeaderPipelineFilterBase<TPackageInfo> : TerminatorPipelineFilter<TPackageInfo>
    where TPackageInfo : class
{
    private static readonly char TAB = '\t';
    private static readonly char COLON = ':';
    private static readonly ReadOnlyMemory<byte> HeaderTerminator = "\r\n\r\n"u8.ToArray();

    protected abstract IPipelineFilter<TPackageInfo> GetNextPipelineFilter(HttpRequest header);

    public HttpHeaderPipelineFilterBase()
        : base(HeaderTerminator)
    {
    }

    protected override TPackageInfo DecodePackage(ref ReadOnlySequence<byte> buffer)
    {
        var request = ParseHttpHeaderItems(buffer);

        var nextFilter = GetNextPipelineFilter(request);

        NextFilter = nextFilter;

        return default;
    }

    private static HttpRequest ParseHttpHeaderItems(ReadOnlySequence<byte> header)
    {
        var headerText = header.GetString(Encoding.UTF8);
        var reader = new StringReader(headerText);
        var firstLine = reader.ReadLine();

        if (string.IsNullOrEmpty(firstLine))
            return null;

        var items = new NameValueCollection();

        var prevKey = string.Empty;
        var line = string.Empty;

        while (!string.IsNullOrEmpty(line = reader.ReadLine()))
        {
            if (line.StartsWith(TAB) && !string.IsNullOrEmpty(prevKey))
            {
                var currentValue = items.Get(prevKey);
                items[prevKey] = currentValue + line.Trim();
                continue;
            }

            int pos = line.IndexOf(COLON);

            if (pos <= 0)
                continue;

            string key = line.Substring(0, pos);

            if (!string.IsNullOrEmpty(key))
                key = key.Trim();

            if (string.IsNullOrEmpty(key))
                continue;

            var valueOffset = pos + 1;

            if (line.Length <= valueOffset) //No value in this line
                continue;

            var value = line.Substring(valueOffset);

            if (!string.IsNullOrEmpty(value) && value.StartsWith(' ') && value.Length > 1)
                value = value.Substring(1);

            var existingValue = items.Get(key);

            if (string.IsNullOrEmpty(existingValue))
            {
                items.Add(key, value);
            }
            else
            {
                items[key] = existingValue + ", " + value;
            }

            prevKey = key;
        }

        var metaInfo = firstLine.Split(' ');

        if (metaInfo.Length != 3)
        {
            // invalid first line
            return null;
        }

        return new HttpRequest(metaInfo[0], metaInfo[1], metaInfo[2], items);
    }
}